1 module hip.ai.steering;
2 version(Test):
3 import hip.math.random;
4 import hip.math.utils;
5 public import hip.math.utils:AxisNavigation;
6 public import hip.math.vector;
7 
8 Vector3 seek(Vector3 target, Vector3 position, float speed, float dt)
9 {
10     Vector3 dir = target-position;
11     dir.normalize;
12     return dir*speed*dt;
13 }
14 Vector3 seekAndStop(Vector3 target, Vector3 position, float speed, float dt)
15 {
16     Vector3 dir = target-position;
17     Vector3 velocity = dir;
18     velocity.normalize;
19     velocity*=speed*dt;
20 
21     if(velocity.mag > dir.mag)
22         return dir;
23     return velocity;
24 }
25 
26 
27 Vector3 arrive(Vector3 target, Vector3 position, float slowdownFactor, float speed, float dt)
28 {
29     Vector3 dir = target-position;
30     slowdownFactor = (dir.mag/slowdownFactor);
31     dir.normalize;
32     return dir*(speed*slowdownFactor*dt);
33 }
34 
35 
36 Vector3 pursuit(Vector3 target, Vector3 targetVelocity, Vector3 position, float speed, float dt, float predictionFactor = 1)
37 {
38     Vector3 dir = (target+(targetVelocity*predictionFactor)) - position;
39     dir.normalize;
40     return dir*(speed*dt);
41 }
42 
43 Vector3 flee(Vector3 target, Vector3 position, float speed, float dt)
44 {
45     Vector3 dir = target-position;
46     dir.normalize;
47     return dir*(-speed*dt);
48 }
49 
50 Vector3 evade(Vector3 target, Vector3 targetVelocity, Vector3 position, float speed, float dt,float predictionFactor = 1)
51 {
52     Vector3 dir = (target+(targetVelocity*predictionFactor)) - position;
53     dir.normalize;
54     return dir*(-speed*dt);
55 }
56 
57 enum WanderAxis
58 {
59     xy, yz, xz, zx, zy, yx
60 }
61 
62 Vector3 wander(
63     Vector3 velocity,
64     Vector3 displacement,
65     float circleDistance,
66     float circleRadius,
67     ref float wanderAngle,
68     float angleChangeFactor,
69     float speed,
70     float dt,
71     AxisNavigation axis = AxisNavigation.xy
72 )
73 {
74     Vector3 circle = velocity;
75     circle.normalize;
76     circle*= circleDistance;
77     displacement.normalize;
78     displacement*= circleRadius;
79 
80     wanderAngle+= Random.rangef(0, 2) * angleChangeFactor - angleChangeFactor*0.5f;
81     displacement = toCircleBounds(displacement, wanderAngle, axis);
82 
83     Vector3 wanderForce = circle+displacement;
84 
85     return wanderForce * (speed*dt);
86 }
87 
88 struct PathFollowerStatus
89 {
90     Vector3[] waypoints;
91     uint currentWaypoint;
92     this(Vector3[] waypoints)
93     {
94         this.waypoints = waypoints;
95         currentWaypoint = 0;
96     }
97 
98     pragma(inline, true) Vector3 getWaypoint(){return waypoints[currentWaypoint];}
99     pragma(inline, true) bool hasFinished(){return currentWaypoint >= waypoints.length;}
100     pragma(inline, true) void checkAdvance(ref Vector3 pos, float range)
101     {
102         if(!hasFinished && getWaypoint.distance(pos) <= range)
103         {
104             currentWaypoint++;
105         }
106     }
107 }
108 
109 Vector3 pathFollow(Vector3 position, ref PathFollowerStatus status, float speed, float dt, float minRange=0)
110 {
111     status.checkAdvance(position, minRange);
112     if(status.hasFinished)
113         return Vector3.zero;
114     return seekAndStop(status.getWaypoint, position, speed, dt);
115 }
116 
117 
118 //Incomplete
119 void flocking(
120     Vector3 position, float perceptionRadius,
121     ref Vector3 alignment,
122     Vector3[] groupPosition, Vector3[] groupAlignment
123 )
124 {
125 
126     Vector3 alignmentSteering = Vector3.zero;
127     size_t groupSize = 0;
128     for(size_t i = 0; i < groupPosition.length; i++)
129     {
130         if(groupPosition[i] != position && position.distance(groupPosition[i]) <= perceptionRadius)
131         {
132             alignmentSteering = alignmentSteering + groupPosition[i];
133             groupSize++;
134         }
135     }
136     if(groupSize != 0)
137     {
138         alignmentSteering/= groupSize;
139         alignment = alignment - alignmentSteering;
140     }
141     
142 }